package vip.xiaonuo.client.modular.wxpay.util;

import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付签名工具类
 * 
 * @author Vincent
 */
@Slf4j
public class WxPaySignUtil {

    /**
     * 生成小程序调起支付的参数
     *
     * @param appId 小程序ID
     * @param prepayId 预支付交易会话标识
     * @param privateKeyPath 商户私钥文件路径
     * @return 支付参数
     */
    public static Map<String, String> createPaySignature(String appId, String prepayId, String privateKeyPath) {
        try {
            String privateKeyContent;
            
            // 根据路径类型读取私钥内容
            if (privateKeyPath.startsWith("classpath:")) {
                // 从classpath读取私钥
                String classpathLocation = privateKeyPath.substring("classpath:".length());
                privateKeyContent = loadPrivateKeyFromClasspath(classpathLocation);
            } else {
                // 从文件系统读取私钥
                privateKeyContent = new String(Files.readAllBytes(Paths.get(privateKeyPath)));
            }
            
            return createPaySignatureWithPrivateKey(appId, prepayId, privateKeyContent);
        } catch (IOException e) {
            log.error("读取私钥文件失败", e);
            throw new RuntimeException("读取私钥文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 从classpath加载私钥内容
     *
     * @param classpathLocation classpath下的资源路径
     * @return 私钥内容
     * @throws IOException 读取异常
     */
    private static String loadPrivateKeyFromClasspath(String classpathLocation) throws IOException {
        log.info("从classpath加载私钥文件: {}", classpathLocation);
        ClassPathResource resource = new ClassPathResource(classpathLocation);
        try (InputStream inputStream = resource.getInputStream()) {
            byte[] bytes = StreamUtils.copyToByteArray(inputStream);
            return new String(bytes, StandardCharsets.UTF_8);
        } catch (IOException e) {
            log.error("从classpath加载私钥文件失败: {}", classpathLocation, e);
            throw e;
        }
    }
    
    /**
     * 使用私钥内容生成小程序调起支付的参数
     *
     * @param appId 小程序ID
     * @param prepayId 预支付交易会话标识
     * @param privateKeyContent 商户私钥内容
     * @return 支付参数
     */
    public static Map<String, String> createPaySignatureWithPrivateKey(String appId, String prepayId, String privateKeyContent) {
        try {
            Map<String, String> payInfo = new HashMap<>();
            // 构建支付参数
            String nonceStr = RandomUtil.randomString(32);
            long timestamp = System.currentTimeMillis() / 1000;
            String packageValue = "prepay_id=" + prepayId;
            String signType = "RSA";
            
            // 设置支付参数
            payInfo.put("appId", appId);
            payInfo.put("timeStamp", String.valueOf(timestamp));
            payInfo.put("nonceStr", nonceStr);
            payInfo.put("package", packageValue);
            payInfo.put("signType", signType);
            
            // 构建签名字符串
            String signatureStr = appId + "\n" + timestamp + "\n" + nonceStr + "\n" + packageValue + "\n";
            
            // 加载私钥
            PrivateKey privateKey = loadPrivateKey(privateKeyContent);
            
            // 计算签名
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
            String paySign = Base64.getEncoder().encodeToString(sign.sign());
            
            // 设置签名
            payInfo.put("paySign", paySign);
            
            return payInfo;
        } catch (Exception e) {
            log.error("生成支付参数签名失败", e);
            throw new RuntimeException("生成支付参数签名失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 加载私钥
     *
     * @param privateKeyContent 私钥内容字符串
     * @return 私钥对象
     */
    private static PrivateKey loadPrivateKey(String privateKeyContent) throws Exception {
        if (privateKeyContent.contains("-----BEGIN PRIVATE KEY-----")) {
            // 移除PEM格式的头部和尾部
            privateKeyContent = privateKeyContent.replaceAll("-+BEGIN PRIVATE KEY-+", "")
                    .replaceAll("-+END PRIVATE KEY-+", "")
                    .replaceAll("\\s", "");
        }
        
        byte[] keyBytes = Base64.getDecoder().decode(privateKeyContent);
        java.security.spec.PKCS8EncodedKeySpec spec = new java.security.spec.PKCS8EncodedKeySpec(keyBytes);
        java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(spec);
    }
} 